/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package my.cbr.application;

import java.awt.Dimension;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import jcolibri.casebase.CachedLinealCaseBase;
import jcolibri.casebase.LinealCaseBase;
import jcolibri.cbraplications.StandardCBRApplication;
import jcolibri.cbrcore.CBRCase;
import jcolibri.cbrcore.CBRCaseBase;
import jcolibri.cbrcore.CBRQuery;
import jcolibri.cbrcore.CaseComponent;
import jcolibri.cbrcore.Connector;
import jcolibri.connector.DataBaseConnector;
import jcolibri.evaluation.Evaluator;
import jcolibri.evaluation.evaluators.HoldOutEvaluator;
import jcolibri.evaluation.evaluators.LeaveOneOutEvaluator;
import jcolibri.exception.ExecutionException;
import jcolibri.method.retrieve.NNretrieval.NNConfig;
import jcolibri.method.retrieve.NNretrieval.NNScoringMethod;
import jcolibri.method.retrieve.NNretrieval.similarity.global.Average;
import jcolibri.method.retrieve.RetrievalResult;
import jcolibri.method.retrieve.selection.SelectCases;
import my.cbr.casedescriptions.CaseDescription;
import my.cbr.casedescriptions.CaseSolution;
import my.cbr.database.MySQLDBServer;
import my.cbr.database.model.AquacultureProdUnit;
import my.cbr.database.model.AquacultureSite;
import my.cbr.database.model.FishDeath;
import my.cbr.database.model.measurement.MeasurementType;
import my.cbr.database.model.measurement.OxygenInstance;
import my.cbr.gui.CaseVisualization;
import my.cbr.gui.StartUpDialog;
import my.cbr.gui.QueryDialog;
import my.cbr.gui.ResultDialog;
import my.cbr.gui.RetainDialog;
import my.cbr.gui.RevisionDialog;
import my.cbr.gui.SimilarityDialog;

/**
 *
 * @author Geir Ole
 */
public class CBRApplication implements StandardCBRApplication{

    private CBRCaseBase caseBase;
    private Connector connector;
    public static final String DATABASE_CONFIG_FILE = "my/cbr/database/resources/databaseconfig.xml";
    private static CBRApplication INSTANCE = null;
    private static JFrame main;
    private SimilarityDialog similarityDialog;
    private ResultDialog resultDialog;
    private RevisionDialog revisionDialog;
    private RetainDialog retainDialog;
    public boolean evaluationMode = false;
    public boolean visualizationMode = false;


    public static CBRApplication getInstance()
    {
        if (INSTANCE == null)
        {
            INSTANCE = new CBRApplication();
        }
        return INSTANCE;
    }
    
    private CBRApplication(){
    }
    
    /**
     * 
     * @throws ExecutionException 
     */
    public void configure() throws ExecutionException {
        main = new JFrame("CBRFishFarming");
        main.setResizable(false);
        main.setUndecorated(true);
        /*
         * FileIO usefull class to access external files!
         * */
        JLabel label = new JLabel(new ImageIcon(jcolibri.util.FileIO.findFile("/jcolibri/test/main/jcolibri2.jpg"))) ;
        main.getContentPane().add(label);
        main.pack();

        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        main.setBounds((screenSize.width - main.getWidth())/2,(screenSize.height - main.getHeight())/2,main.getWidth() ,main.getHeight() );
        main.setVisible(true);

        if(evaluationMode)
            this.caseBase = new CachedLinealCaseBase();
        else
            this.caseBase = new LinealCaseBase();
        
        MySQLDBServer.init();
        this.connector = new DataBaseConnector();
        this.connector.initFromXMLfile(jcolibri.util.FileIO.findFile(CBRApplication.DATABASE_CONFIG_FILE));

            


        similarityDialog = new SimilarityDialog(main);
        resultDialog = new ResultDialog(main);
        revisionDialog = new RevisionDialog(main);
        retainDialog = new RetainDialog(main);
    }

    /**
     * 
     * @return
     * @throws ExecutionException 
     */
    public CBRCaseBase preCycle() throws ExecutionException {
        this.caseBase.init(this.connector);

        // Print the cases
        java.util.Collection<CBRCase> cases = this.caseBase.getCases();
        int count = 0;
        
        ArrayList<CBRCase> emptyCases = new ArrayList<CBRCase>();
        for(CBRCase c: cases)
        {
            //System.out.println(c);
            CaseSolution cs = (CaseSolution) c.getSolution();
            if(cs.getRisk().equals("No death"))
            {
                emptyCases.add(c);
                System.out.println(c);
                count++;
            }
        }
        for(CBRCase c: emptyCases)
            cases.remove(c);
        
        for(CBRCase c: cases)
        {
            System.out.println(c);
        }
        System.out.println(count+" number of cases with no solutions have been deleted from the case base");
        return this.caseBase;
    }
    
    

    /**
     * 
     * @param query
     * @throws ExecutionException 
     */
    public void cycle(CBRQuery query) throws ExecutionException {
        if(!evaluationMode)
            similarityDialog.setVisible(true);
        NNConfig simConfig = similarityDialog.getSimilarityConfig();
        simConfig.setDescriptionSimFunction(new Average());

        //execute NN
        Collection<RetrievalResult> eval = NNScoringMethod.evaluateSimilarity(caseBase.getCases(), query, simConfig);

        //select k cases
        Collection<CBRCase> selectedcases = SelectCases.selectTopK(eval, similarityDialog.getK());
        //eval = SelectCases.selectTopKRR(eval, similarityDialog.getK());
        
        System.out.println("Query case:"+query.toString());
        // Print the retrieval
        System.out.println("Retrieved cases:");
        for(RetrievalResult nse: eval) {
                System.out.println(nse.getEval() + " : " + nse);
        }

        //evaluation
        if(evaluationMode)
        {
            Double result = new Double(eval.iterator().next().getEval());
            Evaluator.getEvaluationReport().addDataToSeries("Similarity", result);
        }
        //show result
        else{
            resultDialog.showCases(eval, selectedcases);
            resultDialog.setVisible(true);
            
            // create a new array to send to revision
            Collection<CBRCase> selectedcases2 = new ArrayList<CBRCase>();
            for(CBRCase cbrcase : selectedcases)
            {
                CaseDescription currentQuery = (CaseDescription) query.getDescription();
                CaseSolution caseSolution = new CaseSolution();
                CaseSolution solution = (CaseSolution) cbrcase.getSolution();
                caseSolution.setDeathRatio(solution.getDeathRatio());
                caseSolution.setAggregatedCount(solution.getAggregatedCount());
                caseSolution.setRisk(solution.getRisk());
//                caseSolution.setCaseDescription(currentQuery);
//                currentQuery.setCaseSolution(caseSolution);
                
                CBRCase currentCase = new CBRCase();
                currentCase.setDescription(currentQuery);
                currentCase.setSolution(caseSolution);
                selectedcases2.add(currentCase);
            }
            
            revisionDialog.showCases(selectedcases2);
            revisionDialog.setVisible(true);
            
            retainDialog.showCases(selectedcases2, caseBase.getCases().size());
            retainDialog.setVisible(true);
            Collection<CBRCase> casesToRetain = retainDialog.getCasestoRetain();
            caseBase.learnCases(casesToRetain);
            System.out.println(casesToRetain.size());
        }
    }
    
    /**
     * 
     * @throws ExecutionException 
     */
    public void postCycle() throws ExecutionException {
        if(this.connector!=null)
            this.connector.close();
        MySQLDBServer.shutdown();
    }

    public void evaluateSystem()
    {
        jcolibri.util.ProgressController.clear();
        jcolibri.util.ProgressController.register(new jcolibri.test.main.SwingProgressBar(), LeaveOneOutEvaluator.class);

//        // Hold-Out evaluation
//        HoldOutEvaluator evaluator = new HoldOutEvaluator();
//        evaluator.init(this);
//        evaluator.HoldOut(10, 2);    //5% split, 3 repetitions

        // Leave-One-Out evaluation
        LeaveOneOutEvaluator evaluator = new LeaveOneOutEvaluator();
        evaluator.init(this);
        evaluator.LeaveOneOut();


        System.out.println(Evaluator.getEvaluationReport());
        jcolibri.evaluation.tools.EvaluationResultGUI.show(Evaluator.getEvaluationReport(), "Evaluation", true);
    }
    
    public void visualizeCaseBase()
    {
        NNConfig simConfig = similarityDialog.getSimilarityConfig();
        simConfig.setDescriptionSimFunction(new Average());
        CaseVisualization.visualize(this.caseBase.getCases(), simConfig);
        //jcolibri.extensions.visualization.CasesVisualization.visualize(this.caseBase.getCases(), simConfig);
    }
    
    public static void main(String[] args){
        //boolean restart = true;
        //while(restart)
        //{
        StartUpDialog cd = new StartUpDialog(null);
        cd.setVisible(true);
        
        CBRApplication app = getInstance();
                
        try
        {
            if(app.evaluationMode)
                app.evaluateSystem();

            else
            {
                //configure
                app.configure();
                app.preCycle();
            
                QueryDialog qf = new QueryDialog(main);

                boolean _continue = true;
                if(!app.visualizationMode)
                {
                    // normal cbr routine
                    while(_continue)
                    {
                        qf.reSetFrame();
                        qf.setVisible(true);
                        CBRQuery query = qf.getQuery();
                        app.cycle(query);

                         //ask if cont
                        int ans = javax.swing.JOptionPane.showConfirmDialog(null,"CBRcycle finished, query again?","Cycle finished",javax.swing.JOptionPane.YES_NO_OPTION);
                        _continue = ( ans == javax.swing.JOptionPane.YES_OPTION) ;
                    }
                    app.postCycle();
                    System.exit(0);
                }
                else
                {
                    app.visualizeCaseBase();
                    app.postCycle();
                }
            }

        }catch(Exception e)
        {
            e.printStackTrace();
            org.apache.commons.logging.LogFactory.getLog(CBRApplication.class).error(e);
            javax.swing.JOptionPane.showMessageDialog(null, e.getMessage());
            System.exit(-1);
        }
    }
}
